package com.uxsino.simo.indicator.retractor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.uxsino.simo.networkentity.EntityInfo;
import com.uxsino.simo.query.QueryTemplate;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.uxsino.commons.utils.config.ConfigProp;
import com.uxsino.reactorq.model.INDICATOR_TYPE;
import com.uxsino.simo.indicator.AGGREGATE_FUNCTION;
import com.uxsino.simo.query.QueryContext;

public class SNMPSimpleValueRetractor extends SimpleValueRetractor {
    private static Logger logger = LoggerFactory.getLogger(SNMPSimpleValueRetractor.class);

    @ConfigProp(name = "exclude_value")
    private String excludeValue;

    @ConfigProp(name = "max_value")
    private String maxValue;

    @ConfigProp(name = "min_value")
    private String minValue;

    @ConfigProp(name = "aggr")
    private String aggr;

    public SNMPSimpleValueRetractor(INDICATOR_TYPE valueType) {
        super(valueType);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object doRetract(EntityInfo entity, QueryContext ctxt, QueryTemplate qt, Object obj) {

        if (obj == null) {
            logger.error("value must be not-null.");
            return null;
        }
        Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) obj;
        if (map.size() != 1) {
            logger.error("value must be one.{}", JSON.toJSONString(map));
            return null;
        }
        Object r = null;
        Map<String, String> values = map.values().iterator().next();
        if (StringUtils.isBlank(aggr)) {
            if (values.values().size() != 1) {
                logger.error("value must be one.{}", JSON.toJSONString(values.values()));
                return null;
            } else {
                r = values.values().iterator().next();
            }

        } else {
            if (values.values().isEmpty()) {
                logger.error("value must be not-null.");
                return null;
            }
            List<Double> list = new ArrayList<>();
            AGGREGATE_FUNCTION aggrFun = null;
            try {
                aggrFun = AGGREGATE_FUNCTION.valueOf(aggr.toUpperCase());
            } catch (Exception e) {
                logger.error("non-support aggregate function [{}].", aggr);
                return null;
            }
            values.values().forEach(v -> {
                if (!StringUtils.isNumeric(v)) {
                    logger.error("value must be numeric.");
                    return;
                }
                list.add(Double.valueOf(v));
            });
            switch (aggrFun) {
            case AVG:
                r = list.stream().collect(Collectors.averagingDouble(Double::valueOf));
                break;
            case COUNT:
                r = list.stream().filter(v -> null != v).count();
                break;
            case COUNT_ALL:
                r = list.size();
                break;
            case MAX:
                r = list.stream().reduce(Double::max).orElse(null);
                break;
            case MIN:
                r = list.stream().reduce(Double::min).orElse(null);
                break;
            case SUM:
                r = list.stream().reduce(Double::sum).orElse(null);
                break;
            case CUSTOM:
                logger.error("non-support aggregate function [{}].", aggr);
                break;
            default:
                break;
            }
        }
        return convertValue(r);
    }
}
